package com.common.core.results;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.common.core.exception.code.BaseErrorCode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @auther zhangwj
 * @date 2021/7/26 下午3:48
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class PageResult<T> extends Result implements Serializable {

    private static final long serialVersionUID = 1L;

    PageResult() {
    }

    @JSONField(ordinal = 5)
    private Page<T> payload;

    public void total(long total) {
        if (null != this.payload) {
            this.payload.setTotal(total);
        }
    }

    public void data(List<T> data) {
        if (null != this.payload) {
            this.payload.setArray(data);
        }
    }

    public static <T> PageResult<T> of(int current, int size) {
        Page<T> page = new Page<>();
        page.setArray(Collections.emptyList());
        page.setTotal(0);
        page.setCurrent(current);
        page.setSize(size);
        return pageResult(page);
    }

    public static <T> PageResult<T> of(List<T> data, int current, int size) {
        Page<T> page = new Page<>();
        page.init(data, current, size);
        return pageResult(page);
    }


    public static <T> PageResult<T> failed(int errNum, String errMsg) {
        PageResult<T> response = new PageResult<>();
        response.setSuccess(false);
        response.setErrNum(errNum);
        response.setErrMsg(errMsg);
        return response;
    }

    public static <T> PageResult<T> failed(BaseErrorCode errorCode) {
        PageResult<T> response = new PageResult<>();
        response.setSuccess(false);
        response.setErrNum(errorCode.getErrNum());
        response.setErrMsg(errorCode.getErrMsg());
        return response;
    }

    @Override
    public String toString() {
        return JSON.toJSONString(this, SerializerFeature.WriteMapNullValue);
    }

    @Data
    public static class Page<T> {

        @JSONField(ordinal = 1)
        private int current = 1;

        @JSONField(ordinal = 2)
        private int size = 10;

        @JSONField(ordinal = 3)
        private long total = 0;

        @JSONField(ordinal = 4)
        private long totalPage = 0;

        @JSONField(serialize = false, ordinal = 5)
        private long pageStartRow = 0;

        @JSONField(serialize = false, ordinal = 6)
        private long pageEndRow = 0;

        @JSONField(ordinal = 7)
        private boolean hasNextPage = false;

        @JSONField(ordinal = 8)
        private boolean hasPreviousPage = false;

        @JSONField(ordinal = 9)
        private List<T> array;

        public void setTotal(long count) {
            init(count, this.current, this.size);
        }

        public void setArray(List<T> data) {
            this.array = data;
           // init(data, this.current, this.size);
        }

        public void setSize(int size) {
            this.size = Math.max(size, 1);
        }

        public void setCurrent(int current) {
            this.current = Math.max(current, 1);
        }

        public List<T> getArray() {
            if (null == array) {
                return Collections.emptyList();
            }
            return new ArrayList<>(array);
        }

        private long getTotalPages() {
            return this.total % this.size == 0 ? this.total
                    / this.size : (this.total / this.size) + 1;
        }

        private void init(List<T> list, int current, int size) {
            if (1 >= current) {
                this.setCurrent(1);
            } else {
                this.setCurrent(current);
                hasPreviousPage = true;
            }
            this.size = size;
            total = list.size();
            if ((total % size) == 0) {
                totalPage = (total / size);
            } else {
                totalPage = total / size + 1;
            }
            hasNextPage = this.getCurrent() < totalPage;
            if ((long) this.getCurrent() * size < total) {
                // 判断是否为最后一页
                pageStartRow = pageEndRow - size;
                pageEndRow = (long) this.getCurrent() * size;
            } else {
                pageEndRow = total;
                if (0 == total) {
                    pageStartRow = 0;
                } else {
                    pageStartRow = size * (totalPage - 1);
                }
            }
            this.array = getLists(list, current);
        }

        private void init(long count, int current, int size) {
            if (1 >= current) {
                this.setCurrent(1);
            } else {
                this.setCurrent(current);
                hasPreviousPage = true;
            }
            this.size = size;
            total = count;
            if ((total % size) == 0) {
                totalPage = total / size;
            } else {
                totalPage = total / size + 1;
            }
            hasNextPage = this.getCurrent() < totalPage;
            if ((long) this.getCurrent() * size < total) {
                // 判断是否为最后一页
                pageEndRow = (long) this.getCurrent() * size;
                pageStartRow = pageEndRow - size;
            } else {
                pageEndRow = total;
                if (0 == total) {
                    pageStartRow = 0;
                } else {
                    pageStartRow = size * (totalPage - 1);
                }
            }
        }

        public List<T> getLists(List<T> data, int current) {
            this.current = current;
            if (current == 0) {
                this.setCurrent(1);
            } else {
                this.setCurrent(current);
            }
            this.disposePage();
            if ((long) this.getCurrent() * size < total) {
                // 判断是否为最后一页
                pageEndRow = (long) this.getCurrent() * size;
                pageStartRow = pageEndRow - size;
            } else {
                pageEndRow = total;
                pageStartRow = size * (totalPage - 1);
            }

            List<T> objects = null;
            if (!CollectionUtils.isEmpty(data)) {
                objects = data.subList((int) pageStartRow, (int) pageEndRow);
            }
            return objects;
        }

        private void disposePage() {
            if (current == 0) {
                current = 1;
            }
            hasPreviousPage = (current - 1) > 0;
            hasNextPage = current < totalPage;
        }

        @JSONField(name = "isEmpty", ordinal = 10)
        public boolean isEmpty() {
            return array == null || array.isEmpty();
        }
    }
}
